package com.market.goods.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.market.goods.dao.es.MarketGoodsDocument;
import com.market.goods.dao.mapper.MarketGoodsMapper;
import com.market.goods.dao.mongo.MarketGoodsDetails;
import com.market.goods.dao.po.MarketGoodsPO;
import com.market.goods.dao.po.QueryJoinPO;
import com.market.goods.service.MarketGoodsService;
import com.market.goods.web.vo.MarketGoodsVO;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.*;
import org.elasticsearch.action.support.replication.ReplicationResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.DistanceUnit;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
import java.util.Objects;


@Slf4j
@Service
public class MarketGoodsServiceImpl implements MarketGoodsService {

    @Autowired
    MarketGoodsMapper marketGoodsMapper;

    @Resource
    RestHighLevelClient restHighLevelClient;

    @Autowired
    MongoTemplate mongoTemplate;


    @Override
    public void insertSelective(MarketGoodsPO marketGoodsPO) {
        marketGoodsMapper.insertSelective(marketGoodsPO);
    }

    @Override
    public void inserBulktEs(String indexName, List<Object> objects) {
        BulkRequest bulkRequest = new BulkRequest();
        for (Object object : objects) {
            IndexRequest indexRequest = new IndexRequest(indexName);
            String esJson = JSONObject.toJSONString(object);
            indexRequest.source(esJson, XContentType.JSON);
            bulkRequest.add(indexRequest);
        }
        try {
            BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.info("insertEsIOException={}", e);
        }
    }

    @Override
    public List<MarketGoodsPO> qryMarketGoodsByShopId(String shopId) {
        MarketGoodsPO qryPo = new MarketGoodsPO();
        qryPo.setShopId(shopId);
        return marketGoodsMapper.select(qryPo);
    }

    @Override
    public MarketGoodsPO qryMarketGoodsByGoodId(String goodId) {
        MarketGoodsPO qryPo = new MarketGoodsPO();
        qryPo.setGoodsId(goodId);
        return marketGoodsMapper.selectOne(qryPo);
    }

    @Override
    public List<QueryJoinPO> queryJoin(List<String> goodIds) {
        return marketGoodsMapper.queryJoin(goodIds);
    }

    @Override
    public List<MarketGoodsVO> queryByEs(MarketGoodsVO marketGoodsVO) {
        List<MarketGoodsVO> marketGoodsVOS = Lists.newArrayList();
//        log.info("queryByEsMarketGoodsVO={}", marketGoodsVO);
//        RangeQueryBuilder rangeQueryBuilder = null;
//        if (Objects.nonNull(marketGoodsVO.getStartTime()) && Objects.nonNull(marketGoodsVO.getEndTime())) {
//            rangeQueryBuilder = QueryBuilders.rangeQuery("createdTime").gte(marketGoodsVO.getStartTime().getTime())
//                    .lte(marketGoodsVO.getEndTime().getTime());
//        }
//        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
//        boolQueryBuilder.filter(rangeQueryBuilder);
//        SearchRequest searchRequest = new SearchRequest(indexName);
//        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        searchSourceBuilder.query(boolQueryBuilder);
//        searchRequest.source(searchSourceBuilder);
//        List<SearchHit> searchHits = scrollSearchAll(restHighLevelClient, 3000L, searchRequest);
//        if (Objects.nonNull(searchHits) && searchHits.size() > 0) {
//            for (SearchHit searchHit : searchHits) {
//                String sourceAsString = searchHit.getSourceAsString();
////                log.info("queryByEsSourceAsString={}",sourceAsString);
//                marketGoodsVOS.add(JSON.parseObject(sourceAsString,MarketGoodsVO.class));
//            }
//        }

        return marketGoodsVOS;
    }

    @Override
    public void insertMarketGoodsDetailsForMongodb(MarketGoodsDetails marketGoodsDetails) {

    }



    // 获取附近的人
    public void testGetNearbyPeople(String index, String type, double lat, double lon) throws IOException {
        // lon, lat位于谦的坐标，查询距离于谦1米到1000米
//        FilterBuilder builder = geoDistanceRangeFilter("location").point(lon, lat).from("1m").to("100m").optimizeBbox("memory").geoDistance(GeoDistance.PLANE);
        GeoDistanceQueryBuilder location = QueryBuilders.geoDistanceQuery("location").point(lat, lon).distance(100, DistanceUnit.METERS);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.filter(location);
        //        restHighLevelClient
//        srb.setPostFilter(location);
        // 获取距离多少公里 这个才是获取点与点之间的距离的
//        GeoDistanceSortBuilder sort = SortBuilders.geoDistanceSort("location", lat, lon);
//        sort.unit(DistanceUnit.METERS);
//        sort.order(SortOrder.ASC);
//        sort.point(lat, lon);
//        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
//        sourceBuilder.aggregation(sort);
//        sourceBuilder.query(boolQueryBuilder);
//        sourceBuilder.from(0);
//        // 获取记录数，默认10
//        sourceBuilder.size(20000);

//        SearchRequest searchRequest = new SearchRequest(indexName);
//        searchRequest.source(sourceBuilder);
//        SearchResponse response = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);


    }

    /**
     * 游标查询
     *
     * @param restHighLevelClient
     * @param scrollTimeOut
     * @param searchRequest
     * @return
     */
    private List<SearchHit> scrollSearchAll(RestHighLevelClient restHighLevelClient, Long scrollTimeOut, SearchRequest searchRequest) {
        List<SearchHit> resultSearchHits = Lists.newArrayList();
        try {
            Scroll scroll = new Scroll(TimeValue.timeValueMillis(scrollTimeOut));
            searchRequest.scroll(scroll);
            SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);
            String scrollId = searchResponse.getScrollId();
            log.info("scrollSearchAllGetScrollId={}", scrollId);
            SearchHit[] hits = searchResponse.getHits().getHits();
            while (isNotEmpty(hits)) {
                for (SearchHit hit : hits) {
                    resultSearchHits.add(hit);
                }
                SearchScrollRequest searchScrollRequest = new SearchScrollRequest(scrollId);
                searchScrollRequest.scroll(scroll);
                SearchResponse searchScrollResponse = restHighLevelClient.scroll(searchScrollRequest, RequestOptions.DEFAULT);
                scrollId = searchScrollResponse.getScrollId();
//                log.info("whileScrollSearchAllGetScrollId={}", scrollId);
                hits = searchScrollResponse.getHits().getHits();
            }
            //及时清除es快照,释放资源
            ClearScrollRequest clearScrollRequest = new ClearScrollRequest();
            clearScrollRequest.addScrollId(scrollId);
            restHighLevelClient.clearScroll(clearScrollRequest, RequestOptions.DEFAULT);
        } catch (Exception e) {
            log.error("scrollSearchAllException={}", e);
        }

        return resultSearchHits;
    }

    private boolean isNotEmpty(SearchHit[] hits) {
        if (hits == null || hits.length == 0) {
            return false;
        } else {
            return true;
        }
    }

}
